Ack, accidentally removed the index
[clinton/website/site/unknownlamer.org.git] / Metaobject Protocols.html
CommitLineData
2aff8b5c 1<?xml version="1.0" encoding="utf-8" ?>
2<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
3 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
4<html xmlns="http://www.w3.org/1999/xhtml">
5 <head>
6 <title>Metaobject Protocols</title>
7 <meta name="generator" content="muse.el" />
8 <meta http-equiv="Content-Type"
9 content="text/html; charset=utf-8" />
a7e21d41 10 <link href="http://feeds.unknownlamer.org/rss/site-updates"
11 rel="alternate" type="application/rss+xml" title="Updates Feed" />
12
2aff8b5c 13<link rel="stylesheet" href="default.css" media="screen" />
14 </head>
15 <body>
16 <h1>Metaobject Protocols</h1>
17 <div class="contents">
18<dl>
19<dt>
20<a href="#sec1">Background</a>
21</dt>
22<dd>
23<dl>
24<dt>
25<a href="#sec2">Object Protocols</a>
26</dt>
27<dt>
28<a href="#sec3">CLOS Way of OO</a>
29</dt>
30<dd>
31<dl>
32<dt>
a7e21d41 33<a href="#sec4">Classes for Scratch Data and Types</a>
2aff8b5c 34</dt>
35<dt>
a7e21d41 36<a href="#sec5">Generics with Methods that Implement Protocols</a>
2aff8b5c 37</dt>
38</dl>
39</dd>
40</dl>
41</dd>
42<dt>
43<a href="#sec6">Limitations of Default Language Behavior</a>
44</dt>
45<dd>
46<dl>
47<dt>
48<a href="#sec7">Slot Storage</a>
49</dt>
50<dt>
51<a href="#sec8">Design Patterns</a>
52</dt>
53</dl>
54</dd>
55<dt>
56<a href="#sec9">Metasoftware</a>
57</dt>
58<dd>
59<dl>
60<dt>
61<a href="#sec10">Runtime Generated Classes</a>
62</dt>
63<dt>
64<a href="#sec11">Object Inspection</a>
65</dt>
66</dl>
67</dd>
68<dt>
69<a href="#sec12">Metaobject Protocols</a>
70</dt>
71<dd>
72<dl>
73<dt>
74<a href="#sec13">Limited/Generalized Internals of the Implementation</a>
75</dt>
76<dt>
77<a href="#sec14">Classes of MOPs</a>
78</dt>
79<dd>
80<dl>
81<dt>
82<a href="#sec15">Reflective</a>
83</dt>
84<dt>
85<a href="#sec16">Intercessory</a>
86</dt>
87</dl>
88</dd>
89<dt>
90<a href="#sec17">Violation of Encapsulation?</a>
91</dt>
92</dl>
93</dd>
94<dt>
95<a href="#sec18">MOP Design Principles</a>
96</dt>
97<dd>
98<dl>
99<dt>
100<a href="#sec19">Layered Protocol</a>
101</dt>
102<dd>
103<dl>
104<dt>
a7e21d41 105<a href="#sec20">Top Level <strong>Must</strong> Call Lower Level Methods</a>
2aff8b5c 106</dt>
107<dt>
a7e21d41 108<a href="#sec21">Lower Level Methods are Easier to Customize</a>
2aff8b5c 109</dt>
110</dl>
111</dd>
112<dt>
113<a href="#sec22">Functional Where Possible</a>
114</dt>
115<dd>
116<dl>
117<dt>
118<a href="#sec23">Memoization</a>
119</dt>
120<dt>
a7e21d41 121<a href="#sec24">Constant Shared Return Values</a>
2aff8b5c 122</dt>
123</dl>
124</dd>
125<dt>
126<a href="#sec25">Procedural Only Where Neccesary</a>
127</dt>
2aff8b5c 128<dt>
a7e21d41 129<a href="#sec26">Real World</a>
2aff8b5c 130</dt>
131<dd>
132<dl>
133<dt>
a7e21d41 134<a href="#sec27">UCW and Arnesi</a>
2aff8b5c 135</dt>
136<dt>
a7e21d41 137<a href="#sec28">CLSQL</a>
2aff8b5c 138</dt>
139<dt>
a7e21d41 140<a href="#sec29">Elephant</a>
2aff8b5c 141</dt>
142</dl>
143</dd>
144</dl>
145</dd>
146<dt>
a7e21d41 147<a href="#sec30">Sources &amp;amp; Further Reading</a>
2aff8b5c 148</dt>
149<dd>
150<dl>
151<dt>
a7e21d41 152<a href="#sec31">Sources</a>
2aff8b5c 153</dt>
154<dd>
155<dl>
156<dt>
a7e21d41 157<a href="#sec32">The Art of the Metaobject Protocol</a>
2aff8b5c 158</dt>
159<dt>
a7e21d41 160<a href="#sec33">CLOS MOP Specification</a>
2aff8b5c 161</dt>
162<dt>
a7e21d41 163<a href="#sec34">Metaobject Protocols: Why We Want Them and What Else They Can Do</a>
2aff8b5c 164</dt>
165<dt>
a7e21d41 166<a href="#sec35">Why Are Black Boxes so Hard to Reuse?</a>
2aff8b5c 167</dt>
168</dl>
169</dd>
170<dt>
a7e21d41 171<a href="#sec36">Further Reading</a>
2aff8b5c 172</dt>
173<dd>
174<dl>
175<dt>
a7e21d41 176<a href="#sec37">A Metaobject Protocol for C++</a>
2aff8b5c 177</dt>
178<dt>
a7e21d41 179<a href="#sec38">Open Implementations and Metaobject Protocols</a>
2aff8b5c 180</dt>
181</dl>
182</dd>
183</dl>
184</dd>
185</dl>
186</div>
187
188
189<!-- Page published by Emacs Muse begins here --><p>In Fall of 2006 I did a small project on Metaobject Protocols for my
190CS 331 class. Here lie my notes which may perhaps be useful to
191others. I hope to expand them into something more useful over time.</p>
192
193<h2><a name="sec1" id="sec1"></a>
194Background</h2>
195
196<h3><a name="sec2" id="sec2"></a>
197Object Protocols</h3>
198
199<p class="first">An object protocol is a set of methods and specification of the
200interactions between the methods which provide some generic behavior
201(e.g. of a sequence) that are then implemented by classes which
202conform to the protocol (e.g. a vector or list). In most object
203systems a class contains both the methods which implement a protocol
204and the data used by the implementation. The intent is to emulate
205state machines which pass messages between each other.</p>
206
207
208<h3><a name="sec3" id="sec3"></a>
209CLOS Way of OO</h3>
210
211<p class="first">The Common Lisp Object System (CLOS) is different. It separates
212the data and method concepts into classes and generics. A class
213contains data fields only, and a generic has methods specialized for
214certain types attached to it. This seems a bit weird at first, but is
215significantly more powerful as it encourages complete encapsulation
216through its use of classes primarily for method specialization rather
217than for state storage.</p>
218
2aff8b5c 219<h4><a name="sec4" id="sec4"></a>
a7e21d41 220Classes for Scratch Data and Types</h4>
2aff8b5c 221
222<p class="first">In CLOS classes store data in slots (which are the same as data
223members). Encapsulation is not provided; any bit of code can use
224<code>slot-value</code> to access or set the value of a slot. This may seem odd at
225first, but encapsulation is of questionable importance as the slots
226are meant only to be used by the protocol defined around the class.</p>
227
a7e21d41 228<p>Classes are defined with <code>defclass</code></p>
2aff8b5c 229
230<pre class="src">
a7e21d41 231(<span style="color: #b9d3ee;">defclass</span> <span style="color: #98fb98;">name</span> (superclasses ...)
2aff8b5c 232 ((slot-name <span style="color: #b0c4de;">:accessor</span> slot-accessor ...)
233 ...)
234 (class-options ...))
235
a7e21d41 236(<span style="color: #b9d3ee;">defclass</span> <span style="color: #98fb98;">example</span> ()
2aff8b5c 237 ((foo <span style="color: #b0c4de;">:accessor</span> foo-of <span style="color: #b0c4de;">:initform</span> 5)))
238
a7e21d41 239(<span style="color: #b9d3ee;">defclass</span> <span style="color: #98fb98;">example-child</span> (example)
2aff8b5c 240 ((bar <span style="color: #b0c4de;">:accessor</span> bar-of <span style="color: #b0c4de;">:initform</span> (list 1 2 3))))
241</pre>
242
a7e21d41 243<p>Slot defintions have several options; the above example shows only the
2aff8b5c 244<code>:accessor</code> and <code>:initform</code> options which are the most commonly
245used. <code>:accessor</code> generates an accessor for the slot (e.g. if you have
a7e21d41 246an instance of <code>example</code> you can <code>(setf (foo-of some-example-instance)
247'some-value)</code> to set and <code>(foo-of some-example-instance)</code> to access the
2aff8b5c 248value). <code>:initform</code> provides a default initial value for the slot as a
a7e21d41 249symbolic expression to be evaluated when an instance is created in the
250lexical environment of the class definition.</p>
2aff8b5c 251
252
253<h4><a name="sec5" id="sec5"></a>
a7e21d41 254Generics with Methods that Implement Protocols</h4>
2aff8b5c 255
256<p class="first">Generics are like normal functions in Lisp, but they only provide a
257lambda list (parameter list). Methods are added to the generic which
a7e21d41 258specialize on the types of their parameters and provide an
259implementation. This allows writing rich layered protocols which can
260enable selective modification of individual facets with minimal code.</p>
2aff8b5c 261
262<pre class="src">
a7e21d41 263(<span style="color: #b9d3ee;">defgeneric</span> <span style="color: #87cefa;">generic</span> (parameters ...)
2aff8b5c 264 (options) ...)
265
a7e21d41 266(<span style="color: #b9d3ee;">defmethod</span> <span style="color: #87cefa;">generic-name</span> ((parameter type) parameter ...)
2aff8b5c 267 <span style="color: #b3b3b3;">"documentation string"</span>
268 body)
269
a7e21d41 270(<span style="color: #b9d3ee;">defgeneric</span> <span style="color: #87cefa;">foo</span> (bar baz quux)
2aff8b5c 271 (<span style="color: #b0c4de;">:documentation</span> <span style="color: #b3b3b3;">"Process the baz with the quux capacitor to make the
272foo widget fly into the sky at warp speed"</span>))
273
a7e21d41 274(<span style="color: #b9d3ee;">defmethod</span> <span style="color: #87cefa;">foo</span> ((bar example) baz (quux capacitor))
2aff8b5c 275 (launch bar (process-with quux baz)))
276</pre>
277
278<p>A method lambda list differs from a normal lambda list only in that it
279can specify the type of the parameter using the notation <code>(name type)</code>.
280Note also that methods can specialize on the types of every
281argument and not just the first one. This is quite powerful for
282reasons outside of the scope of this presentation.</p>
283
284
285
286
287<h2><a name="sec6" id="sec6"></a>
288Limitations of Default Language Behavior</h2>
289
290<p class="first">The behavior of a language is a compromise between many competing
a7e21d41 291issues that attempts to be as generally useful as possible so that
292<em>most</em> applications will have no issue with the default behavior. There
293are, however, certain applications that could be cleanly written with
294minor modifications to the behavior of the language, but would be
295impossible or quite difficult to write otherwise.</p>
2aff8b5c 296
297<h3><a name="sec7" id="sec7"></a>
298Slot Storage</h3>
299
300<p class="first">Most languages choose to preallocate storage for all of the slots of
a7e21d41 301an instance. Now imagine a contact database that stores information
302about people in slots of a class. There may be dozens of slots, but
303often many of them will be left blank. If slot storage is preallocated
304much memory will be wasted and the database may not be able to fit
305into the memory of the hardware it must run on (perhaps for financial
306reasons, huge datasets, etc.).</p>
2aff8b5c 307
308<p>To save memory the author of the contact database must implement his
309own system to store properties and allocate them lazily. This
310represents a fair bit of effort, and would implement a system that
a7e21d41 311differed from the existing slot system of classes only regarding slot
312storage.</p>
2aff8b5c 313
a7e21d41 314<p>It would be useful if there were a way to customize slot allocation in
315instances. The customizations would be minor and require overriding
2aff8b5c 316only the initial allocation behavior and the behavior of the first
317assignment to the slot. It is a a trivial problem in a language that
a7e21d41 318allows customization of these behaviors.</p>
2aff8b5c 319
320
321<h3><a name="sec8" id="sec8"></a>
322Design Patterns</h3>
323
324<p class="first">Design Patterns are generalized versions of common patterns found in
325programs. Many of them are merely methods to get around deficiencies
326in the language, and can be quite messy to implement in some
a7e21d41 327languages. Ideally a pattern would be subsumed by the language, but
328real world contraints require language standards to remain fairly
329static.</p>
2aff8b5c 330
331
332
333<h2><a name="sec9" id="sec9"></a>
334Metasoftware</h2>
335
336<p class="first">Some types of programs could be written easily if the language were
a7e21d41 337customizable but are nearly impossible to write when it is not.</p>
2aff8b5c 338
339<h3><a name="sec10" id="sec10"></a>
340Runtime Generated Classes</h3>
341
342<p class="first">Say you wanted to write a video game where players could create their
343own objects, attach behaviors to the objects, and perhaps mix
344different objects together to create new ones. When you abstract the
345problem this looks just like an object system! Wouldn't it be nice if
a7e21d41 346your program could create new classes and methods on the fly portably?</p>
2aff8b5c 347
348
349<h3><a name="sec11" id="sec11"></a>
350Object Inspection</h3>
351
a7e21d41 352<p class="first">Imagine you were developing a complicated program with many different
353objects that interacted in fairly complex ways. A tool to inspect the
354structure of objects while debugging would be quite useful, but in a
355traditional language would be impossible to implement portably. This
356could force you to purchase a certain compiler implementation which
357provided an inspector, and even then would likely not be customizable.</p>
2aff8b5c 358
359<p>This problem can be generalized to apply to most debugging tools; it
360would be useful to write such tools portably because users of the
361<em>language</em> and not the <em>compiler</em> need to debug software. Sharing
362infrastructure would result in better tools (more developers), and
a7e21d41 363save the man-years of wasted effort that comes with having to rewrite
364unportable tools from scratch multiple times.</p>
2aff8b5c 365
366
367
368<h2><a name="sec12" id="sec12"></a>
369Metaobject Protocols</h2>
370
371<h3><a name="sec13" id="sec13"></a>
372Limited/Generalized Internals of the Implementation</h3>
373
a7e21d41 374<p class="first">A Metaobject Protocol (MOP) is a generalized and limited subset of the
375underlying language implementation. It is limited to allow multiple
376implementation strategies; this, along with careful design, is
377essential because programming language research is ever advancing and
378new techniques for creating more reliable and faster implementations
379are still being discovered.</p>
2aff8b5c 380
381<p>This subset of the implementation is exported as a set of methods on
a7e21d41 382metaobjects. Thus the language is implemented in itself. The system
383can then be customized using the extension and overriding features of
384the language itself.</p>
2aff8b5c 385
386
387<h3><a name="sec14" id="sec14"></a>
388Classes of MOPs</h3>
389
390<h4><a name="sec15" id="sec15"></a>
391Reflective</h4>
392
a7e21d41 393<p class="first">A reflective MOP provides an interface to information <em>about</em> the
394running system. It exposes class relationships, the methods attached
395to a generic, etc. A reflective MOP often provides some functionality
396for creating new classes at runtime. Smalltalk was one of the first
397languages to expose a reflective MOP.</p>
2aff8b5c 398
399<h5>Example: Object Inspector</h5>
400
2aff8b5c 401<pre class="src">
a7e21d41 402(<span style="color: #b9d3ee;">defgeneric</span> <span style="color: #87cefa;">example-inspect</span> (instance)
2aff8b5c 403 (<span style="color: #b0c4de;">:documentation</span> <span style="color: #b3b3b3;">"Simple object inspector using CLOS MOP"</span>))
404
a7e21d41 405(<span style="color: #b9d3ee;">defmethod</span> <span style="color: #87cefa;">example-inspect</span> ((instance t))
2aff8b5c 406 (format t <span style="color: #b3b3b3;">"Simple Object~% Value: ~S~%"</span> instance))
407
a7e21d41 408(<span style="color: #b9d3ee;">defmethod</span> <span style="color: #87cefa;">example-inspect</span> ((instance standard-object))
409 (<span style="color: #b9d3ee;">let</span> ((class (class-of instance)))
2aff8b5c 410 (format t <span style="color: #b3b3b3;">"Class: ~S, Superclasses: ~S~%"</span>
411 (class-name class)
412 (mapcar #'class-name
413 (class-precedence-list class)))
a7e21d41 414 (<span style="color: #b9d3ee;">let</span> ((slot-names (mapcar #'slot-definition-name
2aff8b5c 415 (class-slots class))))
416 (format t <span style="color: #b3b3b3;">"Slots: ~%~{ ~S~%~}"</span> slot-names)
417 (inspect-loop slot-names instance #'example-inspect))))
418
a7e21d41 419(<span style="color: #b9d3ee;">defun</span> <span style="color: #87cefa;">inspect-loop</span> (slots instance inspector)
2aff8b5c 420 (format t <span style="color: #b3b3b3;">"Enter slot to inspect or :pop to go up one level: "</span>)
421 (finish-output)
a7e21d41 422 (<span style="color: #b9d3ee;">let*</span> ((slot (read))
2aff8b5c 423 (found-slot (member slot slots)))
a7e21d41 424 (<span style="color: #b9d3ee;">cond</span> (found-slot
2aff8b5c 425 (funcall inspector (slot-value instance slot))
426 (funcall inspector instance))
427 ((eq slot <span style="color: #b0c4de;">:pop</span>) t)
428 (t
429 (format t <span style="color: #b3b3b3;">"~S is invalid. Valid slot names: ~S~%"</span>
430 slot
431 slots)
432 (inspect-loop slots instance inspector)))))
433</pre>
434
435
a7e21d41 436<h5>Example: Runtime Generated Classes and Methods</h5>
437
438
439
440<h4><a name="sec16" id="sec16"></a>
441Intercessory</h4>
442
443<p class="first">Intercessory MOPs allow the user to customize language behavior by
444implementing methods which override certain aspects of the language
445behavior. This class of MOPs are what make MOPs especially
446powerful. No longer must a problem be restructured to fit the
447implementation language; the underyling language can be reshaped to
448fit the task at hand, and obfuscation of the intended structure of the
449application can be avoided.</p>
450
451<h5>Example: Lazily Allocated Slots</h5>
452
453
454<h5>Example: Observer Design Pattern</h5>
2aff8b5c 455
a7e21d41 456<p>A simple implementation of the observer pattern is under 100 lines,
2aff8b5c 457and the user level code requires only a single line of code to make
458any existing class observable.</p>
459
460<p>In a language lacking a MOP, implementing the observer pattern
461requires modifying every accessor of a class to explicitly invoke any
462observers, and neccesitates the addition of a mixin class to the class
463heirarchy. The fact that an object can be observed is a meta property
464of the class, and forcing it to be implemented at the application
465level dirties the inheritance heirarchy and adds uneccesary meta
466details to the program.</p>
467
468<pre class="src">
469<span style="color: #ff7f24;">;;; </span><span style="color: #ff7f24;">This metaclass adds a slot to instances which use it, and so the
470</span><span style="color: #ff7f24;">;;; </span><span style="color: #ff7f24;">system is defined in its own package to avoid name conflicts
a7e21d41 471</span>(<span style="color: #b9d3ee;">defpackage</span> <span style="color: #98fb98;">:observer</span>
2aff8b5c 472 (<span style="color: #b0c4de;">:use</span> <span style="color: #b0c4de;">:cl</span> #+sbcl <span style="color: #b0c4de;">:sb-mop</span>)
473 (<span style="color: #b0c4de;">:export</span> observable register-observer unregister-observer))
474
a7e21d41 475(<span style="color: #b9d3ee;">in-package</span> <span style="color: #b0c4de;">:observer</span>)
2aff8b5c 476
477<span style="color: #ff7f24;">;;; </span><span style="color: #ff7f24;">Metaclass
a7e21d41 478</span>(<span style="color: #b9d3ee;">defclass</span> <span style="color: #98fb98;">observable</span> (standard-class)
2aff8b5c 479 ()
480 (<span style="color: #b0c4de;">:documentation</span> <span style="color: #b3b3b3;">"Metaclass for observable objects"</span>))
481
a7e21d41 482(<span style="color: #b9d3ee;">defmethod</span> <span style="color: #87cefa;">compute-slots</span> ((class observable))
2aff8b5c 483 <span style="color: #b3b3b3;">"Add a slot for storing observers to observable instances"</span>
484 (cons (make-instance 'standard-effective-slot-definition
485 <span style="color: #b0c4de;">:name</span> 'observers
486 <span style="color: #b0c4de;">:initform</span> '(make-hash-table)
a7e21d41 487 <span style="color: #b0c4de;">:initfunction</span> #'(<span style="color: #b9d3ee;">lambda</span> () (make-hash-table)))
2aff8b5c 488 (call-next-method)))
489
a7e21d41 490(<span style="color: #b9d3ee;">defmethod</span> <span style="color: #87cefa;">validate-superclass</span> ((class observable)
2aff8b5c 491 (super standard-class))
492 t)
493
a7e21d41 494(<span style="color: #b9d3ee;">defun</span> <span style="color: #87cefa;">register-observer</span> (instance slot-name key closure)
2aff8b5c 495 (register-observer-with-class (class-of instance)
496 instance
497 slot-name
498 key
499 closure))
500
a7e21d41 501(<span style="color: #b9d3ee;">defun</span> <span style="color: #87cefa;">unregister-observer</span> (instance slot-name key)
2aff8b5c 502 (unregister-observer-with-class (class-of instance)
503 instance
504 slot-name
505 key))
506
a7e21d41 507(<span style="color: #b9d3ee;">defun</span> <span style="color: #87cefa;">get-observers</span> (instance slot-name)
2aff8b5c 508 (get-observers-with-class (class-of instance)
509 instance
510 slot-name))
511
a7e21d41 512(<span style="color: #b9d3ee;">defun</span> <span style="color: #87cefa;">add-observer-table</span> (instance slot-name)
2aff8b5c 513 (setf (gethash slot-name (slot-value instance
514 'observers))
515 (make-hash-table)))
516
a7e21d41 517(<span style="color: #b9d3ee;">defgeneric</span> <span style="color: #87cefa;">register-observer-with-class</span> (class instance slot-name key closure))
518(<span style="color: #b9d3ee;">defgeneric</span> <span style="color: #87cefa;">unregister-observer-with-class</span> (class
2aff8b5c 519 instance
520 slot-name
521 key))
522
a7e21d41 523(<span style="color: #b9d3ee;">defmethod</span> <span style="color: #87cefa;">register-observer-with-class</span> ((class observable)
2aff8b5c 524 instance
525 slot-name
526 key
527 closure)
528 (setf (gethash key
529 (or (gethash slot-name
530 (slot-value instance 'observers))
531 <span style="color: #ff7f24;">;; </span><span style="color: #ff7f24;">Lazily add observer hash tables
532</span> (add-observer-table instance slot-name)))
533 closure))
534
a7e21d41 535(<span style="color: #b9d3ee;">defmethod</span> <span style="color: #87cefa;">unregister-observer-with-class</span> ((class observable)
2aff8b5c 536 instance
537 slot-name
538 key)
539 (remhash key (gethash slot-name
540 (slot-value instance 'observers))))
541
a7e21d41 542(<span style="color: #b9d3ee;">defmethod</span> <span style="color: #87cefa;">get-observers-with-class</span> ((class observable)
2aff8b5c 543 instance
544 slot-name)
545 (gethash slot-name (slot-value instance 'observers)))
546
a7e21d41 547(<span style="color: #b9d3ee;">defmethod</span> (<span style="color: #87cefa;">setf slot-value-using-class)</span> <span style="color: #b0c4de;">:before</span> (new-value
2aff8b5c 548 (class observable)
549 instance
550 slot)
a7e21d41 551 (<span style="color: #b9d3ee;">let</span> ((slot-name (slot-definition-name slot)))
552 (<span style="color: #b9d3ee;">if</span> (not (eq 'observers slot-name))
553 (<span style="color: #b9d3ee;">let</span> ((observers
2aff8b5c 554 (get-observers instance (slot-definition-name slot))))
a7e21d41 555 (<span style="color: #b9d3ee;">if</span> observers
556 (maphash #'(<span style="color: #b9d3ee;">lambda</span> (key observer)
2aff8b5c 557 (funcall observer
a7e21d41 558 (<span style="color: #b9d3ee;">if</span> (slot-boundp instance slot-name)
2aff8b5c 559 (slot-value instance slot-name)
560 nil)
561 new-value))
562 observers))))))
563</pre>
564
565
a7e21d41 566
567
568
569<h3><a name="sec17" id="sec17"></a>
570Violation of Encapsulation?</h3>
571
572<p class="first">A MOP may seem like a violation of encapsulation by revealing some
573implementation details, but in reality a well designed protocol does
574not reveal anything which was not already exposed. Implementation
575decisions affect users, and some of these details do leak through to
576higher levels (e.g. the memory layout of slots). Implicit in the
577protocol specification are these implementation details, and the MOP
578merely makes this limited subset available for customization.</p>
579
580<p>A MOP makes it possible to customize certain implementation decisions
581that do not <strong>radically</strong> alter the behavior of the base language. The
582conceptual vocabulary of the system retains its meaning, and so code
583written in one dialect can interact with code written in another
584without knowing that they speak different ones.</p>
585
586
587
588<h2><a name="sec18" id="sec18"></a>
589MOP Design Principles</h2>
590
591<h3><a name="sec19" id="sec19"></a>
592Layered Protocol</h3>
593
594<p class="first">A layered protocol design is good for both meta and normal object
595protocols, and enables a combinatorial explosion of customizations to
596the protocol.</p>
597
598<h4><a name="sec20" id="sec20"></a>
599Top Level <strong>Must</strong> Call Lower Level Methods</h4>
600
601<p class="first">The top level methods of a layered protocol are required to call
602certain lower level methods to perform some tasks. This both makes it
603easier to customize the top level methods (which perform very broad
604tasks) by providing some pieces of implementation for the programmer,
605and enables more customization by opening up the replacement of lower
606level functions as a way to alter a small detail of the high level
607behavior.</p>
608
609
610<h4><a name="sec21" id="sec21"></a>
611Lower Level Methods are Easier to Customize</h4>
612
613<p class="first">The lower level methods of a MOP are limited in scope and can be
614implemented easily. Often the desired changes to language behavior are
615minor, and having methods that perform simple tasks which are often
616customized reduces the effort required to extend the system.</p>
617
618
619
620<h3><a name="sec22" id="sec22"></a>
621Functional Where Possible</h3>
622
623<p class="first">Functional protocols are preferred for MOPs (and object protocols in
624general). Functional protocols open up several optimizations for the
625implementation without burdening the user of the protocol.</p>
626
627<h4><a name="sec23" id="sec23"></a>
628Memoization</h4>
629
630<p class="first">Memoization is the process of saving the results of a function call
631for future use. This avoids expensive recomputation of values which
632have not changed (recall that a true function will always return the
633same result when given the same arguments).</p>
634
635<p>A functional MOP can be optimized easily by exploiting this property
636to memoize the return values of calls to expensive operations. A MOP
637must be be very fast to avoid making programs unusably slow, and
638memoization is able to give an appreciable speedup in many cases
639without a significant burden on memory usage.</p>
640
641
642<h4><a name="sec24" id="sec24"></a>
643Constant Shared Return Values</h4>
644
645<p class="first">Disallowing modification of values returned by protocol methods allows
646the implementation to return large data structures by reference to
647avoid expensive copying without having to do expensive data integrity
648checks or copying.</p>
649
650
651
652<h3><a name="sec25" id="sec25"></a>
653Procedural Only Where Neccesary</h3>
654
655<p class="first">Some operations like method invocation are inheretly stateful and so
656must use a procedural protocol. There is no benefit to be gained from
657using a functional protocol, and indeed an attempt would result in
658obtuse code that severely restricted the implementian. Do note that
659only a very small part of method invocation is stateful (the actual
660call), and most of it can be implemented functionally (e.g. computing
661the discriminating function).</p>
662
663
664<h3><a name="sec26" id="sec26"></a>
2aff8b5c 665Real World</h3>
666
a7e21d41 667<h4><a name="sec27" id="sec27"></a>
2aff8b5c 668<a href="http://common-lisp.net/project/ucw/">UCW</a> and <a href="http://common-lisp.net/project/bese/arnesi.html">Arnesi</a></h4>
669
670<p class="first">Arnesi uses the CLOS MOP to implement methods which are transparantly
671rewritten into continuation passing style. This allows their execution
672to be suspended at certain points and resumed later. UCW builds on top
673of this to support a web framework where the statelessness of http is
674hidden from the user; displaying a page suspends the execution of the
675current continuation, and resumes it upon submission. The user level
676code is completely unaware of this.</p>
677
678
a7e21d41 679<h4><a name="sec28" id="sec28"></a>
2aff8b5c 680<a href="http://clsql.b9.com">CLSQL</a></h4>
681
682<p class="first">CLSQL uses the reflective part of the CLOS MOP to map Common Lisp data
683types into SQL types, and the intercessory protocol for slot
684allocation to map slots onto database columns or sql expressions (for
685implementing relational slots).</p>
686
687
a7e21d41 688<h4><a name="sec29" id="sec29"></a>
2aff8b5c 689<a href="http://common-lisp.net/project/elephant/">Elephant</a></h4>
690
691<p class="first">Elephant uses the CLOS MOP to transparantly store any class to disk
a7e21d41 692and handle paging between the disk store and memory efficiently
693without user intervention.</p>
2aff8b5c 694
695
696
697
a7e21d41 698<h2><a name="sec30" id="sec30"></a>
2aff8b5c 699Sources &amp;amp; Further Reading</h2>
700
a7e21d41 701<h3><a name="sec31" id="sec31"></a>
2aff8b5c 702Sources</h3>
703
a7e21d41 704<h4><a name="sec32" id="sec32"></a>
2aff8b5c 705The Art of the Metaobject Protocol</h4>
706
707<h5>Kiczales, Gregor et al. MIT Press 1991</h5>
708
709<p>Highly recommended reading even if you plan to never implement a MOP
710or use the CLOS one. The design principles it recommends are quite
711useful.</p>
712
713
714
a7e21d41 715<h4><a name="sec33" id="sec33"></a>
2aff8b5c 716<a href="http://www.lisp.org/mop/contents.html">CLOS MOP Specification</a></h4>
717
718<p class="first">Specification of the MOP for CLOS defined in <em>The Art of the Metaobject Protocol</em>.</p>
719
720
a7e21d41 721<h4><a name="sec34" id="sec34"></a>
2aff8b5c 722<a href="http://citeseer.ist.psu.edu/399658.html">Metaobject Protocols: Why We Want Them and What Else They Can Do</a></h4>
723
724<p class="first">A short overview of MOP design principles followed by three example
725metaobject protocols for Scheme.</p>
726
727
a7e21d41 728<h4><a name="sec35" id="sec35"></a>
2aff8b5c 729<a href="http://www2.parc.com/csl/groups/sda/projects/oi/towards-talk/transcript.html">Why Are Black Boxes so Hard to Reuse?</a></h4>
730
731<p class="first">Transcription of a talk on the benefits of open implementations of
732software. It first discusses several problems that black box software
733implementations pose, and then presents existing solutions. It shows
734how the existing solutions are insufficient, and then provides
735metaobject protocols as a solution to most of the problems.</p>
736
737
738
a7e21d41 739<h3><a name="sec36" id="sec36"></a>
2aff8b5c 740Further Reading</h3>
741
a7e21d41 742<h4><a name="sec37" id="sec37"></a>
2aff8b5c 743<a href="http://citeseer.ist.psu.edu/chiba95metaobject.html">A Metaobject Protocol for C++</a></h4>
744
745<p class="first">Example of a purely compile time MOP. It implements the functionality
746of a code walker and something similar to the Lisp macro system.</p>
747
748
a7e21d41 749<h4><a name="sec38" id="sec38"></a>
2aff8b5c 750<a href="http://www.parc.com/csl/groups/sda/publications/papers/Kiczales-TUT95/for-web.pdf">Open Implementations and Metaobject Protocols</a></h4>
751
752<p class="first">It is a bit long, but it seems to follow a similar structure to AMOP
753in introducing MOPs and their usefulness. The pages are slides with
754notes, and so the 331 pages might not actually take that long to read.</p>
755
756
757
758
759 <!-- Page published by Emacs Muse ends here -->
760
761 <p class="cke-buttons">
762 <!-- validating badges, any browser, etc -->
763 <a href="http://validator.w3.org/check/referer"><img
764 src="http://www.w3.org/Icons/valid-xhtml10"
765 alt="Valid XHTML 1.0!" /></a>
766
767 <a href="http://www.anybrowser.org/campaign/"><img
768 src="img/buttons/w3c_ab.png" alt="[ Viewable With Any Browser
769 ]" /></a>
770
771 <a href="http://www.debian.org/"><img
772 src="img/buttons/debian.png" alt="[ Powered by Debian ]" /></a>
773
774 <a href="http://hcoop.net/">
775 <img src="img/buttons/hcoop.png"
776 alt="[ Hosted by HCoop]" />
777 </a>
778
779 <a href="http://www.fsf.org/register_form?referrer=114">
780 <img src="img/buttons/fsf_member.png"
781 alt="[ FSF Associate Member ]" />
782 </a>
783 </p>
784
a7e21d41 785<p class="cke-footer">* jeffcovey becomes too groggy to read the directions and becomes
786 the year's first nasal spray overdose fatality.
2aff8b5c 787</p>
788<p class="cke-timestamp">Last Modified:
a7e21d41 789 September 26, 2008</p>
2aff8b5c 790 </body>
791</html>